package org.itboys.mongodb.service;


import com.mongodb.WriteResult;
import org.apache.commons.lang.StringUtils;

import org.itboys.admin.tools.AdminSessionHolder;
import org.itboys.mongodb.core.MongoDataSource;
import org.itboys.mongodb.entity.BaseMongoEntity;
import org.itboys.param.PageResult;
import org.mongodb.morphia.mapping.Mapper;
import org.mongodb.morphia.query.Query;
import org.mongodb.morphia.query.UpdateOperations;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * 作者：jiangxiong
 * 日期：2017年2月8日
 * 联系方式 ：empty90911@126.com
 * 描述：mongo业务层。需要BaseMongo实体配合。只能适应bootstrap，
 * 2017年3月29日，分页需要兼容bootstrap,easyUI和mobile（手机端）。
 * bootstrap分页参数：offset(起始位置)，limit（条数）
 * mobile（手机端）分页参数：pageNumber(页数),pageSize(条数)
 * easyUi分页参数：page(页数),rows(条数)
 *
 *
 * bootstrap排序参数：sort(排序字段)，order（排序方向）
 * mobile（手机端）排序参数：sort(排序字段),order(排序方向)
 * easyUi排序参数：sort(排序字段),order(排序方向)
 */


@Service
public abstract class BaseMongoService<T> implements Serializable {
	protected Logger logger = LoggerFactory.getLogger(getClass());
	//数据起始位置
	public static final String OFFSET = "offset";
	//数据查询条数
	public static final String LIMIT = "limit";
	//数据起始位置_默认
	public static final Integer OFFSET_DEFAULT = 0;//默认0开始
	//数据结束位置_默认
	public static final Integer LIMIT_DEFAULT = 20;//默认20条
	//数据排序字段。
	public static final String SORT = "sort";
	//数据排序字段_默认。
	public static final String SORT_ID = "id";
	//数据排序方向
	public static final String ORDER = "order";
	//数据排序方向_倒序
	public static final String ORDER_DESC = "desc";
	//数据排序方向_正序
	public static final String ORDER_ASC = "asc";
	//模糊查询关键字
	public static final String CONTAINS = "contains:";


	protected abstract MongoDataSource getMongoDataSource();


	@Autowired
	protected IDGeneratorService iDGeneratorService;

	protected Class<T> valueClazz;
	protected Class<T> getEntityClass() {
		if (valueClazz != null) {
			return valueClazz;
		}
		return initAndGetEntityClass();
	}
	private Class<T> initAndGetEntityClass() {
		synchronized (this) {
			if (valueClazz != null) {
				return valueClazz;
			}
			//ParameterizedType type = getSuperClass();
			//2017年2月26日江雄自定义
			ParameterizedType type =  (ParameterizedType)BaseMongoService.class.getGenericSuperclass();
			valueClazz = (Class<T>) type.getActualTypeArguments()[0];
			return valueClazz;
		}
	}

	/**
	 *
	 * @param param 参数。含分页，排序和查询的参数
	 * @param query 对象
	 * @param isPage 是否需要分页
	 * @return
	 */
	private Query<T> prepareQuery(HttpServletRequest request,Map<String, Object> param,Query<T> query,boolean isPage) {
		//2017年3月24日，不建议将request从此处获取
	//	HttpServletRequest request = ServletContextHolder.getRequest();

		Iterator<String> ite=param.keySet().iterator();
		while (ite.hasNext())	{
			String key = ite.next();

			Object value = param.get(key);
			//匹配精确查询查询参数
			if (!key.equalsIgnoreCase(OFFSET) && !key.equalsIgnoreCase(LIMIT)&&
					!key.startsWith(CONTAINS)&&!key.equalsIgnoreCase(SORT)&&!key.equalsIgnoreCase(ORDER)
					) {
				logger.info("--key--"+key+"--value="+value);
				query = query.filter(key, value);
			}
			//匹配模糊查询的参数
			if (key.startsWith(CONTAINS)) {
				key = key.substring(CONTAINS.length(), key.length());
				query = query.field(key).contains(value.toString());
			}

		}

		//String sort =SORT_ID;
		//根据sort和order字段，定义排序字段和顺序
		//排序字段可以从param或request中获取
		String sort=SORT_ID;

		//从param获取sort字段
		if(param.get(SORT)!=null&&
				StringUtils.isNotBlank((String)param.get(SORT))){
			sort=(String)param.get(SORT);
		}
		//从request中获取sort字段

		if (request!=null&& StringUtils.isNotBlank(request.getParameter(SORT))){
			sort=request.getParameter(SORT);
		}

		String order=ORDER_ASC;
		//从param获取order字段
		if(param.get(ORDER)!=null&&
				StringUtils.isNotBlank((String)param.get(ORDER))){
			order=(String)param.get(ORDER);
		}
		//从request中获取sort字段

		if (request!=null&& StringUtils.isNotBlank(request.getParameter(ORDER))){
			order=request.getParameter(ORDER);
		}
		//组装sort。倒序sort字段前加-
		if(order.equalsIgnoreCase(ORDER_DESC)&&!sort.startsWith("-")){
			sort="-"+sort;
		}

		query.order(sort);
		//组装分页参数。不支持EasyUI。支持bootstraptable
		Integer offset=OFFSET_DEFAULT;
		Integer limit=LIMIT_DEFAULT;
		//起始位置和数据数量。分页参数，在request中获取

		/*********************分页参数需要兼容bootstrap,easyUI，mobile（手机端）
		 * bootstrap分页参数：offset(起始位置)，limit（条数）
		* mobile（手机端）分页参数：pageNumber(页数),pageSize(条数)
		* easyUi分页参数：page(页数),rows(条数)**/
		//1，兼容bootstrap
		if(request!=null&&StringUtils.isNotEmpty(request.getParameter("offset"))&&
				StringUtils.isNotEmpty(request.getParameter("limit"))){
			offset=Integer.valueOf(request.getParameter("offset"));
			limit=Integer.valueOf(request.getParameter("limit"));
		}
		//2，兼容easyUI。asyUi分页参数：page(页数),rows(条数)
		if(request!=null&&StringUtils.isNotEmpty(request.getParameter("page"))&&
				StringUtils.isNotEmpty(request.getParameter("rows"))){
			Integer page=Integer.valueOf(request.getParameter("page"));
			Integer rows=Integer.valueOf(request.getParameter("rows"));
			offset=(page-1)*rows;
			limit=rows;
		}
		//3，兼容mobile（手机端）。分页参数：pageNumber(页数),pageSize(条数)
		if(request!=null&&StringUtils.isNotEmpty(request.getParameter("pageNumber"))&&
				StringUtils.isNotEmpty(request.getParameter("pageSize"))){
			Integer pageNumber=Integer.valueOf(request.getParameter("pageNumber"));
			Integer pageSize=Integer.valueOf(request.getParameter("pageSize"));
			offset=(pageNumber-1)*pageSize;
			limit=pageSize;
		}

		//是否需要分页查询
		if(isPage){
			query.offset(offset).limit(limit);
		}
		return query;
	}
	public long getNextId() {
		logger.info("----------getEntityClass().getName()----------"+getEntityClass().getName());
		String entityClassName =getEntityClass().getName();
		//2017年11月25日，天街项目独有的设置
		if(entityClassName.equalsIgnoreCase("org.itboys.mobile.entity.mongo.TianJieMember")){
			logger.info("AAAAAAAAAAAAAAAAAAAAA");
			entityClassName="com.hz.sunday.tianjie.entity.mongo.TianJieMember";
		}
		if(entityClassName.equalsIgnoreCase("org.itboys.mobile.entity.mongo.TianJieCollection")){
			logger.info("BBBBBBBBBBBB");
			entityClassName="com.hz.sunday.tianjie.entity.mongo.TianJieCollection";
		}
		return iDGeneratorService.getNextId(entityClassName);
	}
	private Query<T> getQueryById(Long id) {
		return getMongoDataSource().getQueryById(id, getEntityClass());
	}
	private int update(Long id, UpdateOperations<T> ops) {
		Query<T> query = getQueryById(id);
		return getMongoDataSource().update(query, ops).getUpdatedCount();
	}
	/**
	 * 实例化mongo基类，且设置创建人，创建时间，修改人，修改时间
	 * @param t
	 * @param isCt
	 * @param isUt
	 * @return
	 */
	private BaseMongoEntity initBaseTarentoEntity(T t, boolean isCt, boolean isUt) {
		BaseMongoEntity entity = (BaseMongoEntity)t;
		long now = System.currentTimeMillis();
		if(isCt){
			//设置创建时间
			entity.setCt(now);
			//设置创建人Id和姓名
			if(AdminSessionHolder.getAdminUserId()!=null&&AdminSessionHolder.getAdminUserId().longValue()!=0l){
				entity.setCreator(AdminSessionHolder.getAdminUserId());
			}else{
				entity.setCreator(0l);
			}

		}
		if(isUt){
			//设置创建时间
			entity.setUt(now);
			//设置创建人Id和姓名
			if(AdminSessionHolder.getAdminUserId()!=null&&AdminSessionHolder.getAdminUserId().longValue()!=0l){
				entity.setUpdater(AdminSessionHolder.getAdminUserId());
			}else{
				entity.setUpdater(0l);
			}

		}
		return entity;
	}
	/****----以上是基础Service内部调用的工具类，以下才是可以调用，操作数据库的方法-----**/

	/**
	 * 查询。根据条件查询前n条数据。不分页。
	 * @param param
	 * @param number。此参数可以为空
	 * @return
	 */
	public List<T> list(Map<String, Object> param, Integer number) {

		Query<T> query = getMongoDataSource().createQuery(getEntityClass());
		query = prepareQuery(null,param,query,false);

		//是否只查询前number条数据
		if (number != null) {

			query.limit(number);
		}
		return query.asList();
	}
	/**
	 * 查询。根据条件查询前n条数据。不分页。
	 * @param param
	 * @return
	 */
	public List<T> list(Map<String, Object> param) {

		Query<T> query = getMongoDataSource().createQuery(getEntityClass());
		query = prepareQuery(null,param,query,false);

		return query.asList();
	}

	/**
	 *查询。根据条件查询前n条数据。分页。不需要传入request,分页参数：offSet（起始位置）,limit(结束位置)，sort(排序字段，可以加-前缀定义排序方向)，order(排序方向)
	 * @param containsparam。模糊查询参数。key:value
	 * @param param。精确查询参数.key:value

	 * @return
	 */
	public PageResult<T> containpageQuery(HttpServletRequest request, Map<String, String> containsparam,
										  Map<String, Object> param) {
		Query<T> query = getMongoDataSource().createQuery(getEntityClass());
		if (containsparam != null && containsparam.size() != 0) {
			Iterator<String> itec = containsparam.keySet().iterator();
			while (itec.hasNext()) {
				String key = itec.next();
				String value = containsparam.get(key);
				query.field(key).contains(value.toString());
			}
		}

		//准备查询工具。组装查询参数
		query=prepareQuery(request,param, query,true);
		//统计总数
		final long count = getMongoDataSource().getCount(query);

		return new PageResult<T>(query.asList(), count);
	}

	/**
	 *
	 * *查询。根据条件查询前n条数据。分页。不需要传入request,分页参数：offSet（起始位置）,limit(结束位置)，sort(排序字段，可以加-前缀定义排序方向)，order(排序方向)
	 * @param param。查询参数。精确参数示意：key:value;模糊查询参数：contains:key  : value
	 * @return
	 */
	public PageResult<T> pageQuery(HttpServletRequest request,Map<String, Object> param) {

		Query<T> query = getMongoDataSource().createQuery(getEntityClass());


		//准备查询工具。组装查询参数
		query=prepareQuery(request,param, query,true);
		//统计总数
		final long count = getMongoDataSource().getCount(query);
		return new PageResult<T>(query.asList(), count);
	}
	/**
	 * 查询，按ID,返回单个实体
	 * @param id
	 * @return
	 */
	public T getById(Long id) {
		return getMongoDataSource().createQuery(getEntityClass()).field(Mapper.ID_KEY).equal(id).get();
	}

	/**
	 * 新增
	 * @param t
	 */
	public void save(T t){
		BaseMongoEntity entity = initBaseTarentoEntity(t,true,true);
		entity.setId(getNextId());
		getMongoDataSource().save(t);
	}
	/*
	 * 新增。不登陆情况下新增
	 * @param t
	 */
	public void saveWithoutLogin(T t){
		BaseMongoEntity entity = initBaseTarentoEntity(t,false,false);
		entity.setId(getNextId());
		getMongoDataSource().save(t);
	}
	/**
	 * 批量新增
	 * @param list
	 */
	public void batchSave(List<T> list) {
		for (T t : list) {
			BaseMongoEntity entity =initBaseTarentoEntity(t,true,true);
			entity.setId(getNextId());
		}
		getMongoDataSource().save(list);
	}
	/**
	 * 批量新增。不登陆情况下
	 * @param list
	 */
	public void batchSaveWithoutLogin(List<T> list) {
		for (T t : list) {
			BaseMongoEntity entity =initBaseTarentoEntity(t,false,false);
			entity.setId(getNextId());
		}
		getMongoDataSource().save(list);
	}
	/**
	 * 修改(对象)。如果对象中含有空数据，也会更新，不推荐使用
	 * @param t
	 */

	/*public void update(T t){
			BaseMongoEntity entity = initBaseTarentoEntity(t,false,true);
			getMongoDataSource().save(t);
	}*/
	/**
	 * 修改(对象)。如果对象中含有空数据，不会更新。推荐使用
	 * @param t
	 */
	public void updateExceptEmpty(Long id, T t) {
		try{
			UpdateOperations<T> ops = getMongoDataSource()
					.createUpdateOperations(getEntityClass());
			Class<? extends Object> c = t.getClass();
			Field[] fields = c.getDeclaredFields();
			for (Field field : fields){
				if (!Modifier.isFinal(field.getModifiers())){
					field.setAccessible(true);
					Object obj = field.get(t);

					if (obj != null && !obj.toString().equals("")){
						ops.set(field.getName(), obj);

					}

				}
			}
			//2017年2月27日加入操作人信息
			ops.set("ut",System.currentTimeMillis());
			if(AdminSessionHolder.getAdminUserId()!=null&&AdminSessionHolder.getAdminUserId().longValue()!=0l){
				ops.set("updater",AdminSessionHolder.getAdminUserId());

			}else{
				ops.set("updater",0l);
			}
			//设置姓名，待设置

			this.update(id, ops);
			//	}
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	/**
	 * 修改（字段）。只更新对象中某个字段
	 * @param id
	 * @param filed
	 * @param value
	 * @return
	 */
	public int update(Long id, String filed, Object value) {
		UpdateOperations<T> ops = getMongoDataSource().createUpdateOperations(
				getEntityClass());
		if(value != null){
			ops.set(filed, value);
			//2017年2月27日加入操作人信息
			ops.set("ut",System.currentTimeMillis());
			if(AdminSessionHolder.getAdminUserId()!=null&&AdminSessionHolder.getAdminUserId().longValue()!=0l){
				ops.set("updater",AdminSessionHolder.getAdminUserId());
			}else{
				ops.set("updater",0l);
			}
			//设置姓名，待设置
		}else{
			ops.unset(filed);
		}
		Query<T> query = getQueryById(id);

		return getMongoDataSource().update(query, ops).getUpdatedCount();
	}

	/**
	 * 批量修改
	 * @param list
	 */
	public void batchUpdate(List<T> list) {
		for (T t : list) {
			BaseMongoEntity entity =initBaseTarentoEntity(t,true,true);
		}
		getMongoDataSource().save(list);
	}

	/**
	 * 批量修改。不登陆的情况下
	 * @param list
	 */
	public void batchUpdateWithoutLogin(List<T> list) {
		for (T t : list) {
			BaseMongoEntity entity =initBaseTarentoEntity(t,false,false);
		}
		getMongoDataSource().save(list);
	}


	/**
	 * 删除。假删除,将isDeleted字段标记为删除
	 * @param id
	 */
	public void delete(Long id){
		update(id, "isDeleted", 1);
	}

	/**
	 * 批量删除。假删除，将isDeleted字段标记为删除
	 * @param ids
	 */
	public void Delete(List<Long> ids) {
		for (Long id : ids) {
			delete(id);
		}

	}
	/**删除。假删除，
	 * @param param
	 * @return
	 */
	public void delete(Map<String, Object> param) {
		Iterator<String> ite = param.keySet().iterator();
		Query<T> query = getMongoDataSource().createQuery(getEntityClass());
		//while (ite.hasNext()) {
		while (ite.hasNext())	{
			String key = ite.next();

			Object value = param.get(key);
			//匹配精确查询查询参数
			if (!key.equalsIgnoreCase(OFFSET) && !key.equalsIgnoreCase(LIMIT)&&
					!key.startsWith(CONTAINS)&&!key.equalsIgnoreCase(SORT)&&!key.equalsIgnoreCase(ORDER)
					) {
				query = query.filter(key, value);
			}
			//匹配模糊查询的参数
			if (key.startsWith(CONTAINS)) {
				key = key.substring(CONTAINS.length(), key.length());
				query = query.field(key).contains(value.toString());
			}
		}
		UpdateOperations<T> ops = getMongoDataSource().createUpdateOperations(
				getEntityClass());
		ops.set("isDeleted",1);
		getMongoDataSource().update(query, ops).getUpdatedCount();
		//return getMongoDataSource().delete(query);
	}
	/**
	 * 批量修改。假删除
	 * @param list
	 */
	public void batchDelete(List<T> list) {
		for (T t : list) {
			BaseMongoEntity entity =initBaseTarentoEntity(t,true,true);
			entity.setIsDeleted(1);
		}
		getMongoDataSource().save(list);
	}

	/**
	 * 批量删除。假删除。不登陆的情况下
	 * @param list
	 */
	public void batchDeletedWithoutLogin(List<T> list) {
		for (T t : list) {
			BaseMongoEntity entity =initBaseTarentoEntity(t,false,false);
			entity.setIsDeleted(1);
		}
		getMongoDataSource().save(list);
	}
	/**
	 *
	 * @param param
	 */
	public WriteResult doDelete(Map<String, Object> param) {
		Iterator<String> ite = param.keySet().iterator();
		Query<T> query = getMongoDataSource().createQuery(getEntityClass());
		//while (ite.hasNext()) {
		while (ite.hasNext())	{
			String key = ite.next();
			logger.info("KEY==="+key);
			//System.out.println("KEY==="+key);
			Object value = param.get(key);
			//匹配精确查询查询参数
			if (!key.equalsIgnoreCase(OFFSET) && !key.equalsIgnoreCase(LIMIT)&&
					!key.startsWith(CONTAINS)&&!key.equalsIgnoreCase(SORT)&&!key.equalsIgnoreCase(ORDER)
					) {
				query = query.filter(key, value);
			}
			//匹配模糊查询的参数
			if (key.startsWith(CONTAINS)) {
				key = key.substring(CONTAINS.length(), key.length());
				query = query.field(key).contains(value.toString());
			}
		}

		//	System.err.println(query.asList().size()+"-----------------------------------");
		return getMongoDataSource().delete(query);

	}

	/**
	 * 统计
	 * @param param
	 * @return
	 */
	public long count(Map<String, Object> param) {
		Query<T> query = getMongoDataSource().createQuery(getEntityClass());

		//准备查询工具。组装查询参数
		query=prepareQuery(null,param, query,false);
		//统计总数
		final long count = getMongoDataSource().getCount(query);
		return getMongoDataSource().getCount(query);

	}
}
